package my.sql;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import bean.ConnectionBean;

/**
 * 数据库连接池,用Map<String, Vector<ConnectionBean>>将每种类型的连接进行缓存,键表示是哪种类型的连接,Vector数组中包含该类型下的所有连接.
 * 
 * 连接类型eg:北分中心的连接,中心平台的连接,站级系统的连接(每个站的IP都不一样)
 * 
 * @author gj
 */

public class ConnectionPool {
	// 最大连接池的容量
	private static final int MAX_CONNECTION_POOL_SIZE = 10;

	// 初始化连接池的容量大小
	private static final int INIT_CONNECTION_POOL_SIZE = 1;

	// 键代表连接池的类型
	private static final Map<String, Vector<ConnectionBean>> connectionPoolMap = new HashMap<String, Vector<ConnectionBean>>();

	// 连接mysql
	public static final int MYSQL_DB = 0;

	// 连接sqlserver
	public static final int SQLSERVER_DB = 1;

	static {
		try {
			Class.forName("com.mysql.jdbc.Driver");// 北分中心和站级数据库都是mysql
			Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");// 平台上的sqlserver
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 创建数据库连接
	 * 
	 * @param IP
	 * @param userName
	 * @param passWord
	 * @param DbName
	 * @param dbType
	 * @return
	 */
	private static Connection createConnection(String IP, String userName, String passWord, String DbName, int dbType) {
		Connection con = null;
		try {
			if (dbType == ConnectionPool.MYSQL_DB) {
				con = DriverManager.getConnection("jdbc:mysql://" + IP.trim() + ":8999/" + DbName.trim() + "?user=" + userName.trim() + "&password=" + passWord
						+ "&useUnicode=true&characterEncoding=UTF8&socketTimeout=10000");
			} else if (dbType == ConnectionPool.SQLSERVER_DB) {
				con = DriverManager.getConnection("jdbc:sqlserver://" + IP.trim() + ":1433;DatabaseName=" + DbName.trim() + "", "" + userName.trim() + "", "" + passWord.trim()
						+ "");
			} else {
				con = null;
			}
			System.out.println("init connection: " + con);
		} catch (Exception e) {
			con = null;
			System.out.println("连接初始化失败:" + IP);
		}
		return con;
	}

	/**
	 * 
	 * 创建连接池
	 * 
	 * @param initPoolConnectionSize
	 *            (初始化连接池容量)
	 * @param IP
	 * @param userName
	 * @param passWord
	 * @param DbName
	 * @param dbType
	 * @param typeName
	 * @return
	 */
	private static Vector<ConnectionBean> createConnectionPool(int initPoolConnectionSize, String IP, String userName, String passWord, String DbName, int dbType, String typeName) {
		System.out.println("begin init connectionPool....." + typeName);
		Vector<ConnectionBean> connectionPool = new Vector<ConnectionBean>();
		for (int i = 0; i < initPoolConnectionSize; i++) {
			Connection con = createConnection(IP, userName, passWord, DbName, dbType);
			ConnectionBean conBean = new ConnectionBean(con);
			connectionPool.add(conBean);
		}
		System.out.println("init connectionPool.....end..." + typeName);
		return connectionPool;

	}

	/**
	 * 
	 * 得到一个空闲的连接,如果当前连接处于繁忙状态,并且最大连接数没有超过,就重新在创建新的连接
	 * 
	 * @param IP
	 * @param userName
	 * @param passWord
	 * @param DbName
	 * @param dbType
	 * @param typeName
	 * @return
	 */
	public static synchronized ConnectionBean getFreeConnection(String IP, String userName, String passWord, String DbName, int dbType, String typeName) {
		Vector<ConnectionBean> connectionPool = connectionPoolMap.get(typeName);

		if (connectionPool == null || connectionPool.size() == 0) {
			connectionPool = createConnectionPool(INIT_CONNECTION_POOL_SIZE, IP, userName, passWord, DbName, dbType, typeName);
			connectionPoolMap.put(typeName, connectionPool);
		}

		// 循环所有连接得到空闲的连接
		for (int i = 0; i < connectionPool.size(); i++) {
			ConnectionBean conbean = connectionPool.get(i);
			if (!conbean.isBusy()) {
				conbean.setBusy(true);
				return conbean;
			}
		}
		// 如果所有连接都忙,但是最大连接数没有超过,就创建新的连接并加入到缓存
		if (connectionPool.size() < MAX_CONNECTION_POOL_SIZE) {
			ConnectionBean conBean = new ConnectionBean(createConnection(IP, userName, passWord, DbName, dbType), true);
			connectionPool.add(conBean);
			connectionPoolMap.put(typeName, connectionPool);
			return conBean;
		}
		// 如果上面两种情况都不满足,就等待100ms,继续获取有效连接
		getConnectionForWait(100);
		return getFreeConnection(IP, userName, passWord, DbName, dbType, typeName);
	}

	private static void getConnectionForWait(int millis) {
		try {
			Thread.sleep(millis);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 将连接的状态设置成空闲,没有关闭连接
	 * 
	 * @param con
	 * @param typeName
	 * @param result
	 * @param statement
	 */
	public static synchronized void closeConnection(Connection con, String typeName, ResultSet result, Statement statement) {
		try {
			if (result != null) {
				result.close();
			}
			if (statement != null) {
				statement.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		Vector<ConnectionBean> connectionPool = connectionPoolMap.get(typeName);
		if (connectionPool == null) {
			return;
		}
		for (int i = 0; i < connectionPool.size(); i++) {
			ConnectionBean conbean = connectionPool.get(i);
			if (conbean.getCon() == null) {
				connectionPool.remove(conbean);
				continue;
			}
			if (conbean.getCon() == con) {
				conbean.setBusy(false);
			}
		}
	}

	/**
	 * 关闭某个类型下的所有连接,并清空缓存
	 * 
	 * @param typeName
	 */
	public static synchronized void clearAllConnection(String typeName) {
		Vector<ConnectionBean> connectionPool = connectionPoolMap.get(typeName);
		if (connectionPool == null) {
			return;
		}
		try {
			for (ConnectionBean connectionBean : connectionPool) {
				Connection con = connectionBean.getCon();
				if (con != null) {
					con.close();
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		connectionPool.removeAllElements();// 将改类型下的所有连接全部清除

		System.out.println("already clear all connetions...." + typeName);
	}

	public static void main(String[] args) {
		Connection con1 = ConnectionPool.getFreeConnection("10.190.186.18", "root", "gsmdb112", "gsmapp", ConnectionPool.MYSQL_DB, "10.190.186.18").getCon();
		System.out.println(con1);

	}
}
